use async_trait::async_trait;
use rustcloud_core::{ServiceInstance, ServiceResult, ServiceError, HealthCheck, HealthCheckType};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::sync::RwLock;
use tokio::time::{interval, timeout};
use tracing::{error, warn, info, debug};
use reqwest::Client;

/// 健康检查结果
#[derive(Debug, Clone)]
pub struct HealthCheckResult {
    pub instance: ServiceInstance,
    pub is_healthy: bool,
    pub response_time: Duration,
    pub error_message: Option<String>,
    pub check_time: SystemTime,
}

/// 健康检查状态
#[derive(Debug, Clone)]
pub struct HealthCheckState {
    pub consecutive_failures: u32,
    pub consecutive_successes: u32,
    pub last_check_time: SystemTime,
    pub is_healthy: bool,
    pub total_checks: u64,
    pub total_failures: u64,
}

impl Default for HealthCheckState {
    fn default() -> Self {
        Self {
            consecutive_failures: 0,
            consecutive_successes: 0,
            last_check_time: UNIX_EPOCH,
            is_healthy: true,
            total_checks: 0,
            total_failures: 0,
        }
    }
}

/// 健康检查器接口
#[async_trait]
pub trait HealthChecker: Send + Sync {
    /// 执行健康检查
    async fn check_health(&self, instance: &ServiceInstance, config: &HealthCheck) -> ServiceResult<HealthCheckResult>;
    
    /// 获取检查器名称
    fn name(&self) -> &str;
}

/// HTTP健康检查器
pub struct HttpHealthChecker {
    client: Client,
}

impl HttpHealthChecker {
    pub fn new() -> Self {
        let client = Client::builder()
            .timeout(Duration::from_secs(30))
            .build()
            .unwrap();
        
        Self { client }
    }
}

#[async_trait]
impl HealthChecker for HttpHealthChecker {
    async fn check_health(&self, instance: &ServiceInstance, config: &HealthCheck) -> ServiceResult<HealthCheckResult> {
        let start_time = std::time::Instant::now();
        
        if let HealthCheckType::Http { path, method } = &config.check_type {
            let url = format!("{}://{}{}", instance.scheme, instance.address(), path);
            
            debug!("Performing HTTP health check for {}: {} {}", instance, method, url);
            
            let request = match method.to_uppercase().as_str() {
                "GET" => self.client.get(&url),
                "POST" => self.client.post(&url),
                "PUT" => self.client.put(&url),
                "HEAD" => self.client.head(&url),
                _ => return Err(ServiceError::ConfigurationError(
                    format!("Unsupported HTTP method: {}", method)
                )),
            };
            
            match timeout(config.timeout, request.send()).await {
                Ok(Ok(response)) => {
                    let response_time = start_time.elapsed();
                    let status = response.status();
                    let is_healthy = status.is_success() || status.as_u16() == 404;
                    
                    if !is_healthy {
                        debug!("HTTP health check failed for {}: status {}", instance, status);
                    }
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy,
                        response_time,
                        error_message: if is_healthy { None } else { Some(format!("HTTP {}", status)) },
                        check_time: SystemTime::now(),
                    })
                }
                Ok(Err(e)) => {
                    let response_time = start_time.elapsed();
                    debug!("HTTP health check error for {}: {}", instance, e);
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: false,
                        response_time,
                        error_message: Some(e.to_string()),
                        check_time: SystemTime::now(),
                    })
                }
                Err(_) => {
                    let response_time = start_time.elapsed();
                    debug!("HTTP health check timeout for {}", instance);
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: false,
                        response_time,
                        error_message: Some("Timeout".to_string()),
                        check_time: SystemTime::now(),
                    })
                }
            }
        } else {
            Err(ServiceError::ConfigurationError(
                "HttpHealthChecker requires HTTP health check type".to_string()
            ))
        }
    }
    
    fn name(&self) -> &str {
        "http"
    }
}

/// TCP健康检查器
pub struct TcpHealthChecker;

impl TcpHealthChecker {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait]
impl HealthChecker for TcpHealthChecker {
    async fn check_health(&self, instance: &ServiceInstance, config: &HealthCheck) -> ServiceResult<HealthCheckResult> {
        let start_time = std::time::Instant::now();
        
        if let HealthCheckType::Tcp = &config.check_type {
            let addr = format!("{}:{}", instance.host, instance.port);
            debug!("Performing TCP health check for {}: {}", instance, addr);
            
            match timeout(config.timeout, tokio::net::TcpStream::connect(&addr)).await {
                Ok(Ok(_)) => {
                    let response_time = start_time.elapsed();
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: true,
                        response_time,
                        error_message: None,
                        check_time: SystemTime::now(),
                    })
                }
                Ok(Err(e)) => {
                    let response_time = start_time.elapsed();
                    debug!("TCP health check failed for {}: {}", instance, e);
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: false,
                        response_time,
                        error_message: Some(e.to_string()),
                        check_time: SystemTime::now(),
                    })
                }
                Err(_) => {
                    let response_time = start_time.elapsed();
                    debug!("TCP health check timeout for {}", instance);
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: false,
                        response_time,
                        error_message: Some("Timeout".to_string()),
                        check_time: SystemTime::now(),
                    })
                }
            }
        } else {
            Err(ServiceError::ConfigurationError(
                "TcpHealthChecker requires TCP health check type".to_string()
            ))
        }
    }
    
    fn name(&self) -> &str {
        "tcp"
    }
}

/// 脚本健康检查器
pub struct ScriptHealthChecker;

impl ScriptHealthChecker {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait]
impl HealthChecker for ScriptHealthChecker {
    async fn check_health(&self, instance: &ServiceInstance, config: &HealthCheck) -> ServiceResult<HealthCheckResult> {
        let start_time = std::time::Instant::now();
        
        if let HealthCheckType::Script { command } = &config.check_type {
            debug!("Performing script health check for {}: {}", instance, command);
            
            // 在命令中替换实例变量
            let expanded_command = command
                .replace("{host}", &instance.host)
                .replace("{port}", &instance.port.to_string())
                .replace("{service}", &instance.service_id);
            
            let mut cmd = if cfg!(target_os = "windows") {
                let mut cmd = tokio::process::Command::new("cmd");
                cmd.args(["/C", &expanded_command]);
                cmd
            } else {
                let mut cmd = tokio::process::Command::new("sh");
                cmd.args(["-c", &expanded_command]);
                cmd
            };
            
            match timeout(config.timeout, cmd.output()).await {
                Ok(Ok(output)) => {
                    let response_time = start_time.elapsed();
                    let is_healthy = output.status.success();
                    
                    if !is_healthy {
                        let stderr = String::from_utf8_lossy(&output.stderr);
                        debug!("Script health check failed for {}: {}", instance, stderr);
                    }
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy,
                        response_time,
                        error_message: if is_healthy {
                            None
                        } else {
                            Some(String::from_utf8_lossy(&output.stderr).to_string())
                        },
                        check_time: SystemTime::now(),
                    })
                }
                Ok(Err(e)) => {
                    let response_time = start_time.elapsed();
                    debug!("Script health check error for {}: {}", instance, e);
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: false,
                        response_time,
                        error_message: Some(e.to_string()),
                        check_time: SystemTime::now(),
                    })
                }
                Err(_) => {
                    let response_time = start_time.elapsed();
                    debug!("Script health check timeout for {}", instance);
                    
                    Ok(HealthCheckResult {
                        instance: instance.clone(),
                        is_healthy: false,
                        response_time,
                        error_message: Some("Timeout".to_string()),
                        check_time: SystemTime::now(),
                    })
                }
            }
        } else {
            Err(ServiceError::ConfigurationError(
                "ScriptHealthChecker requires Script health check type".to_string()
            ))
        }
    }
    
    fn name(&self) -> &str {
        "script"
    }
}

/// 健康检查管理器
pub struct HealthCheckManager {
    checkers: HashMap<String, Arc<dyn HealthChecker>>,
    states: Arc<RwLock<HashMap<String, HealthCheckState>>>,
    running_tasks: Arc<RwLock<HashMap<String, tokio::task::JoinHandle<()>>>>,
}

impl HealthCheckManager {
    pub fn new() -> Self {
        let mut checkers: HashMap<String, Arc<dyn HealthChecker>> = HashMap::new();
        
        // 注册默认的健康检查器
        checkers.insert("http".to_string(), Arc::new(HttpHealthChecker::new()));
        checkers.insert("tcp".to_string(), Arc::new(TcpHealthChecker::new()));
        checkers.insert("script".to_string(), Arc::new(ScriptHealthChecker::new()));
        
        Self {
            checkers,
            states: Arc::new(RwLock::new(HashMap::new())),
            running_tasks: Arc::new(RwLock::new(HashMap::new())),
        }
    }
    
    /// 注册自定义健康检查器
    pub fn register_checker(&mut self, name: String, checker: Arc<dyn HealthChecker>) {
        self.checkers.insert(name, checker);
    }
    
    /// 启动健康检查任务
    pub async fn start_health_check(
        &self,
        instance: ServiceInstance,
        config: HealthCheck,
        on_status_change: Option<Box<dyn Fn(ServiceInstance, bool) + Send + Sync>>,
    ) -> ServiceResult<()> {
        let instance_key = format!("{}:{}:{}", instance.service_id, instance.host, instance.port);
        
        // 选择合适的检查器
        let checker_name = match &config.check_type {
            HealthCheckType::Http { .. } => "http",
            HealthCheckType::Tcp => "tcp",
            HealthCheckType::Script { .. } => "script",
        };
        
        let checker = self.checkers.get(checker_name)
            .ok_or_else(|| ServiceError::ConfigurationError(
                format!("Health checker '{}' not found", checker_name)
            ))?
            .clone();
        
        // 初始化状态
        {
            let mut states = self.states.write().await;
            states.insert(instance_key.clone(), HealthCheckState::default());
        }
        
        // 启动健康检查任务
        let states = self.states.clone();
        let instance_key_clone = instance_key.clone();
        let task = tokio::spawn(async move {
            let mut check_interval = interval(config.interval);
            loop {
                check_interval.tick().await;
                
                match checker.check_health(&instance, &config).await {
                    Ok(result) => {
                        let mut states_guard = states.write().await;
                        if let Some(state) = states_guard.get_mut(&instance_key_clone) {
                            state.total_checks += 1;
                            state.last_check_time = result.check_time;
                            
                            if result.is_healthy {
                                state.consecutive_successes += 1;
                                state.consecutive_failures = 0;
                                
                                // 检查是否从不健康恢复为健康
                                if !state.is_healthy && state.consecutive_successes >= config.success_threshold {
                                    state.is_healthy = true;
                                    info!("Instance {} recovered to healthy state", instance);
                                    
                                    if let Some(ref callback) = on_status_change {
                                        callback(instance.clone(), true);
                                    }
                                }
                            } else {
                                state.consecutive_failures += 1;
                                state.consecutive_successes = 0;
                                state.total_failures += 1;
                                
                                // 检查是否从健康变为不健康
                                if state.is_healthy && state.consecutive_failures >= config.failure_threshold {
                                    state.is_healthy = false;
                                    warn!("Instance {} marked as unhealthy: {}", 
                                          instance, result.error_message.unwrap_or_default());
                                    
                                    if let Some(ref callback) = on_status_change {
                                        callback(instance.clone(), false);
                                    }
                                }
                            }
                        }
                    }
                    Err(e) => {
                        error!("Health check error for {}: {}", instance, e);
                    }
                }
            }
        });
        
        // 保存任务句柄
        {
            let mut tasks = self.running_tasks.write().await;
            if let Some(old_task) = tasks.insert(instance_key, task) {
                old_task.abort();
            }
        }
        
        Ok(())
    }
    
    /// 停止健康检查任务
    pub async fn stop_health_check(&self, instance: &ServiceInstance) {
        let instance_key = format!("{}:{}:{}", instance.service_id, instance.host, instance.port);
        
        // 停止任务
        {
            let mut tasks = self.running_tasks.write().await;
            if let Some(task) = tasks.remove(&instance_key) {
                task.abort();
            }
        }
        
        // 清理状态
        {
            let mut states = self.states.write().await;
            states.remove(&instance_key);
        }
    }
    
    /// 获取实例健康状态
    pub async fn get_health_state(&self, instance: &ServiceInstance) -> Option<HealthCheckState> {
        let instance_key = format!("{}:{}:{}", instance.service_id, instance.host, instance.port);
        let states = self.states.read().await;
        states.get(&instance_key).cloned()
    }
    
    /// 获取所有健康状态
    pub async fn get_all_health_states(&self) -> HashMap<String, HealthCheckState> {
        self.states.read().await.clone()
    }
    
    /// 停止所有健康检查任务
    pub async fn shutdown(&self) {
        let mut tasks = self.running_tasks.write().await;
        for (_, task) in tasks.drain() {
            task.abort();
        }
        
        let mut states = self.states.write().await;
        states.clear();
    }
}

impl Default for HealthCheckManager {
    fn default() -> Self {
        Self::new()
    }
}